from nameko.rpc import rpc
import logging as logger
#from script.logger import logger

# modbus_service
import modbus_tk.defines as cst
import modbus_tk.modbus as modbus
import modbus_tk.modbus_tcp as modbus_tcp
#from bitstring import ConstBitStream
import struct

# import xml.dom.minidom
try:
    import xml.etree.cElementTree as ET
except:
    import xml.etree.ElementTree as ET

# http_service
import urllib
import json
import http.cookiejar
#from nameko.web.handlers import http


# scada_service
# import sys
# sys.path.append("..")
from Common.dbhelper import DBHelper
from Common.models import PvMeta, Device_info, Electric_price, Load_data, PV_forecast, Realtime_commands,Day_Ahead
from Common.settings import *
import datetime
from nameko.standalone.rpc import ClusterRpcProxy
import math
import time


class ScadaService:
    name = 'scada_service'

    def __init__(self):
        self.dbhelper = DBHelper(conf=None)
        self.session = self.dbhelper.Session()

    @rpc
    def hello(self, name):
        return "Hello, {}!".format(name)

    @rpc
    def get_histrydata_id(self, id):
        pvmeta = self.session.query(PvMeta).filter(PvMeta.id == 1).first()
        return {
            'code': 0,
            'msg': '',
            'data': pvmeta
        }

    @rpc
    def get_ecode_data(self):
        grid_data = {"10001": [], "10003": {"price": []}, "10103": {"time_stamp": [], "load_p": [], "load_q": []}}
        data = self.session.query(Device_info).all()
        for dev in data:
            grid_data["10001"].append(dev.as_dict())

        data = self.session.query(Electric_price).all()
        for price in data:
            grid_data["10003"]["price"].append(price.price)

        data = self.session.query(Load_data).all()
        for load in data:
            grid_data["10103"]["time_stamp"].append(load.time_stamp)
            grid_data["10103"]["load_p"].append(load.load_p)
            grid_data["10103"]["load_q"].append(load.load_q)
        print(grid_data)
        return json.dumps(grid_data)
        #     {
        #     'code': 0,
        #     'msg': '',
        #     'data': {
        #                 "Parameters":
        #                     {"voltage_control": 1, "economic_dispatch": 0,
        #                      "MicrogridSetting": {"x":0.459, "vnorm":1,"qmin":-200,"qmax":300,"powerFactorLowLimit":0.93},
        #                      "BatterySetting":{"chargeKW":78, "dischargeKW":-100,"socMax":228,"socMin":0}
        #                      },
        #                 "price": [0.5412, 0.5412, 0.5412, 0.5412, 0.5412, 0.5412, 0.8257, 1.1925, 1.1925, 1.1925, 0.8257, 0.8257, 0.8257, 0.8257, 0.8257, 0.8257, 0.8257, 1.1925, 1.1925, 1.1925, 1.1925, 1.1925, 0.5412, 0.5412],
        #                 "pricelable": [0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 0],
        #                 "load": [2247.0, 2163.6, 2142.6, 2118.0, 2170.8, 2190.0, 2261.3999999999996, 2538.0, 3964.2, 4125.0, 4014.0, 4060.2, 3225.0, 3840.6000000000004, 3702.0, 3865.8, 3705.0, 3252.0, 3234.6, 3391.2, 3263.3999999999996, 3336.0, 2959.2, 2481.0],
        #                 "pv":{"kw": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        #                       },
        #                 "Measurement": [
        #                     {"property": "P", "type": "Realtime", "value": 10, "device_id": 1},
        #                     {"property": "Q", "type": "Realtime", "value": 10, "device_id": 1},
        #                     {"property": "Vp", "type": "Realtime", "value": 10, "device_id": 0},
        #                     {"property": "Vq", "type": "Realtime", "value": 5, "device_id": 0},
        #                     {"property": "Ip", "type": "Realtime", "value": 2, "device_id": 0},
        #                     {"property": "Iq", "type": "Realtime", "value": 1, "device_id": 0}
        #                 ]
        #             }
        # }

    @rpc
    def get_weather_condition(self, citycode="CN101270101"):
        # url = 'http://d7.weather.com.cn/fishing/api/v1/tab?stationId=%s' % str(citycode)
        # f = urllib.request.urlopen(url, timeout=0.5)
        # current_weather = str(f.read(), encoding="utf-8")
        # c_result = json.loads(current_weather)
        # if c_result and c_result["status"] == "ok":
        #     # avg_temp = int((float(c_result['result']['dayTemp']) + float(c_result['result']['nightTemp'])) / 2.0)
        #     # weather_condition = {"city": "许昌", "wind_direction": c_result['result']['dayWindDirection'],
        #     #                      "current_temp": str(avg_temp),
        #     #                      "weather": c_result['result']['dayWeatherDes']}
        #     weather_condition = c_result['result']['dayWeatherDes']
        #
        #     return weather_condition
        # else:
        #     return False
        url = 'https://free-api.heweather.net/s6/weather/forecast?location={0}&key={1}'.format(citycode, key)  # 提供三天预报,包括当天
        f = urllib.request.urlopen(url, timeout=0.5)
        current_weather = str(f.read(), encoding="utf-8")
        c_result = json.loads(current_weather)
        # print(c_result)
        if c_result and c_result["HeWeather6"][0]["status"] == "ok":
            daily_forecast = c_result["HeWeather6"][0]["daily_forecast"]
            date_tomorrow = datetime.datetime.now() + datetime.timedelta(days=1)
            date_tomorrow_str = date_tomorrow.strftime('%Y-%m-%d')
            for forecast in daily_forecast:
                if forecast["date"] == date_tomorrow_str:
                    cond_code_d = forecast["cond_code_d"]  # 第二天白天天气代码
                    cond_txt_d = forecast["cond_txt_d"]  # 第二天白天天气文字
                    break

            code = int(cond_code_d)
            if code == 100:
                weather_condition = "晴天"
            elif 100<code<104:
                weather_condition = "多云"
            else:
                weather_condition = "阴雨"

            print(date_tomorrow_str, cond_code_d, cond_txt_d)
            return weather_condition
        else:
            return False

    @rpc
    def get_pv_forecast(self):
        weather_condition = self.get_weather_condition()
        pv_forecast = self.session.query(PV_forecast).all()
        data = {"10104": {"time_stamp": [], "out_p": []}}
        for pv_data in pv_forecast:
            data["10104"]["time_stamp"].append(pv_data.time_stamp)
            if weather_condition == "晴天":
                data["10104"]["out_p"].append(pv_data.out_p_sunny)
            elif weather_condition == "多云":
                data["10104"]["out_p"].append(pv_data.out_p_cloudy)
            elif weather_condition == "阴雨":
                data["10104"]["out_p"].append(pv_data.out_p_overcast)

        return data

    @rpc
    def get_electric_price(self):
        electric_prices = self.session.query(Electric_price).all()
        data = {"10003": {"time_stamp": [], "price": []}}
        for price in electric_prices:
            data["10003"]["time_stamp"].append(price.time_stamp)
            data["10003"]["price"].append(price.price)

        return data

    @rpc
    def get_load_data(self):
        load_data = self.session.query(Load_data).all()
        data = {"10103": {"time_stamp": [], "load_p": [], "load_q": []}}
        for load in load_data:
            data["10103"]["time_stamp"].append(load.time_stamp)
            data["10103"]["load_p"].append(load.load_p)
            data["10103"]["load_q"].append(load.load_q)

        return data

    @rpc
    def realtime_commands_db(self, control_commands=None):
        # control_commands = {"10401": [{"device_id": "1", "type": "Realtime", "p_value": 200.0, "q_value": 0.0},
        #                               {"device_id": "2", "type": "Realtime", "p_value": 500.0, "q_value": 300.0}
        #                               ]
        #                     }
        if control_commands is None:
            return None
        for command in control_commands["10401"]:
            new_command = Realtime_commands(device_id=command["device_id"], type="Realtype",
                                            p_value=command["p_value"], q_value=command["q_value"])
            self.session.add(new_command)
        self.session.commit()
        return 1

    @rpc
    def dayahead_db(self, control_commands=None):
        # control_commands = {"10402": [{"device_id": "1", "type": "DayAhead", "p_value":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],
        #                                "q_value": [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]},
        #                               {"device_id": "2", "type": "DayAhead", "p_value":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],
        #                                "q_value": [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]}
        #                               ]
        #                     }
        if control_commands is None:
            return None
        for command in control_commands["10402"]:
            new_command = Day_Ahead(device_id=command["device_id"], type="DayAhead",
                                    p_value=str(command["p_value"]), q_value=str(command["q_value"]))
            self.session.add(new_command)
        self.session.commit()
        # datas = self.session.query(Day_Ahead).all()
        # for data in datas:
        #     print(data.time_stamp)
        return 1


class ModbusService:
    """
    通过modbus转发协议获取实时数据及下发控制命令
    """
    name = 'modbus_service'

    def __init__(self):
        self.dbhelper = DBHelper(conf=None)
        self.session = self.dbhelper.Session()
        self.modbus_master = self.init_connection()
        self.points = dict()

    @staticmethod
    def init_connection():
        modbus_master = modbus_tcp.TcpMaster(host=hostIP, port=modbus_port, timeout_in_sec=5.0)
        return modbus_master

    @rpc
    def query_data(self, function_code=cst.READ_HOLDING_REGISTERS, starting_address=0, quantity_of_x=1):
        # 根据微控配置文件获取function_code、starting_address、quantity_of_x信息
        # self.points = self.get_pointlist()

        try:
            data = self.modbus_master.execute(slave=1, function_code=function_code,
                                              starting_address=starting_address, quantity_of_x=quantity_of_x)
            return data
        except modbus.ModbusError as error:
            logger.error("error {0}".format(error))
            return 0

    @rpc
    def send_data(self, function_code=cst.WRITE_SINGLE_REGISTER, starting_address=4, output_value=234):
        # 根据微控配置文件获取function_code、starting_address、quantity_of_x信息
        # self.points = self.get_pointlist()
        try:
            flag = self.modbus_master.execute(slave=1, function_code=function_code,
                                              starting_address=starting_address, output_value=output_value)
            # 回读数据，确认是否设置成功
            # requery = self.modbus_master.execute(slave=1, function_code=3,
            #                        starting_address=starting_address, output_value=output_value)
            return flag
        except modbus.ModbusError as error:
            print("error {0}".format(error))
            return False

        # if requery(0) == output_value:
        #     return 1
        # else:
        #     return 0

    @rpc
    def get_realtime_data(self):
        """获取实时数据接口"""
        realtime_data = {"10102": []}
        device_info = self.session.query(Device_info).all()
        device_name = []
        device_ids = dict()
        for device in device_info:
            device_ids[device.device_name] = device.device_id
            device_name.append(device.device_name)

        points_list = self.get_pointlist()["功能码3"]
        # 要求modbus上传的变量寄存器地址连续，变量均为float（4字节）类型
        data = self.query_data(function_code=cst.READ_HOLDING_REGISTERS,
                               starting_address=0, quantity_of_x=len(points_list)*2)

        # z1=hex(data[1]+data[0])[2:]
        #z1 = struct.pack(">HH", data[0], data[1])
        #data1 = struct.unpack('!f', z1)[0]
        #print(bytes(data[0]*65536+data[1]))
        #data1 = ConstBitStream(bytes=z1)

        #print(float.fromhex(hex(data[1]*65536+data[0])))
        # print(points_list)
        if data == 0:
            return data

        for device in device_name:
            temp_dict = {}
            temp_dict["device_id"] = device_ids[device]
            temp_dict["device_name"] = device
            temp_dict["time_stamp"] = time.time()
            temp_dict["status"] = 1

            for point in points_list:
                RegAddr = int(point["RegisterAddress"])
                z1 = struct.pack(">HH", data[RegAddr], data[RegAddr+1])
                data1 = struct.unpack('!f', z1)[0]

                if point["Link"] == device + "@in_active_power":
                    temp_dict["in_active_power"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@in_reactive_power":
                    temp_dict["in_reactive_power"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@in_voltage":
                    temp_dict["in_voltage"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@in_current":
                    temp_dict["in_current"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@out_active_power":
                    temp_dict["out_active_power"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@out_reactive_power":
                    temp_dict["out_reactive_power"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@out_voltage":
                    temp_dict["out_voltage"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@out_current":
                    temp_dict["out_current"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@battery_soc":
                    temp_dict["battery_soc"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@voltage":
                    temp_dict["voltage"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@current":
                    temp_dict["current"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@power":
                    temp_dict["power"] = data1  # data[int(point["RegisterAddress"])]
                elif point["Link"] == device + "@power_factor":
                    temp_dict["power_factor"] = data1  # data[int(point["RegisterAddress"])]

            realtime_data["10102"].append(temp_dict)

        return realtime_data

    @rpc
    def control_in_time(self, control_commands=None):
        """
        控制命令格式见接口规范文档，示例如下：commands变量，
        函数返回值仍为control_commands，格式与输入一致，在对应设备下增加result参数，
        控制命令的执行结果通过result参数返回，1：控制命令执行成功，0：控制命令执行失败
        control_commands = {"10401": [{"device_id": "1", "type": "Realtime", "p_value": 200.0, "q_value": 0.0},
                                      {"device_id": "2", "type": "Realtime", "p_value": 500.0, "q_value": 300.0}
                                      ]
                            }
        """
        if control_commands is None:
            return None
        for command in control_commands["10401"]:
            if command["type"] == "Realtime":
                p_value = command["p_value"]
                q_value = command["q_value"]
               # if (p_value*q_value) <= 0:
               #     command["result"] = 0
               #     continue  #DA
                if command["device_id"] == "1":  # 光伏逆变器
                    if p_value is not None:
                        value = abs(round(p_value/2000.0*100))
                        set_flag = self.send_data(function_code=6, starting_address=1, output_value=value)
                        if set_flag is not False:  #
                            print("有功{}，设置成功".format(set_flag))
                            command["result"] = 1
                        else:
                            command["result"] = 0
                            print("设置失败！")
                    else:
                        pass
                elif command["device_id"] == "2":  # 储能电池
                    if p_value is not None:
                        if q_value is not None and p_value != 0.0:
                            angle = math.atan(q_value/p_value)
                            # pf0 = math.cos(angle) * 100
                            pf1 = round(math.cos(angle) * 100)
                            pf = (pf1 << 8) + 2
                            power = round(p_value/math.cos(angle))  # math.sqrt(p_value ** 2 + q_value ** 2))

                            set_flag1 = self.send_data(function_code=6, starting_address=8, output_value=power)
                            time.sleep(0.05)
                            set_flag2 = self.send_data(function_code=6, starting_address=9, output_value=pf)

                            if set_flag1 is not False and set_flag2 is not False:  #
                                print("功率因素: {},{},{}、功率限制：{} ,设置成功！".format(angle, pf1, hex(pf), power))
                                command["result"] = 1
                            else:
                                command["result"] = 0
                                print("设置失败！")

                        elif p_value == 0.0:
                            set_flag1 = self.send_data(function_code=6, starting_address=8, output_value=0)
                            time.sleep(0.05)
                            set_flag2 = self.send_data(function_code=6, starting_address=9, output_value=25602)

                            if set_flag1 is not False and set_flag2 is not False:  #
                                print("功率因素: {} 功率限制：{} ,设置成功！".format(1, 0))
                                command["result"] = 1
                            else:
                                command["result"] = 0
                                print("设置失败！")

                        else:
                            power = round(p_value)
                            set_flag1 = self.send_data(function_code=6, starting_address=8, output_value=power)
                            time.sleep(0.05)
                            set_flag2 = self.send_data(function_code=6, starting_address=9, output_value=25602)

                            if set_flag1 is not False and set_flag2 is not False:  #
                                print("功率因素: {} 功率限制：{} ,设置成功！".format(1, power))
                                command["result"] = 1
                            else:
                                command["result"] = 0
                                print("设置失败！")
                    else:
                        pass
            elif command["type"] == "DayAhead":
                pass
            time.sleep(0.05)
        return control_commands

    def get_pointlist(self):
        #from Common.settings import xml_path
        tree = ET.parse(xml_path)
        root = tree.getroot()
        points = dict()
        for Link in root.iter("Link"):
            if Link.attrib["Name"] == "modbus_转发":
                for Device in Link.iter("Device"):
                    if Device.attrib["Name"] == "pc上位机":
                        for Type in Device.iter("Type"):
                            pointlist = list()
                            for Point in Type.iter("Point"):
                                pointlist.append(Point.attrib)
                            points[Type.attrib["Value"]] = pointlist
        #print(str(points))
        return points


class HttpService:
    """
    通过http方式可获取历史数据、历史报警信息
    """
    name = 'http_service'

    def __init__(self):
        pass

    @rpc
    def getDataBaseInfo(self, hist_data_info=None):
        """
        :param
        hist_data_info = {}
        link:        String|Array
        当参数值的类型为String时，表示一个点名，例如："API.TEST设备@YC1"；当参数值的类型为String时，
        也可以在结尾处使用"*"，表示所有以"*"前的字符开头的点，例如："API.TEST设备@*"，
        表示所有以"API.TEST设备@"开头的点，也就是，"API"通道下"TEST设备"下的所有点；
        当参数值的类型为Array时，表示一个点列表，例如：["API.TEST设备@YC1", "API.TEST设备@YC2",…]
        startTime:        String
        开始时间，查询历史数据的起始时间，格式：YYYY-MM-DD HH:mm:ss，例：2017-12-29 00:00:00
        endTime:        String
        结束时间，查询历史数据的终止时间，格式：YYYY-MM-DD HH:mm:ss，例：2017-12-30 23:59:59
        """
        if hist_data_info is None:
            return None
        #hostIP1="dr-epic.vicp.io:34005"
        data_url = "http://{}/bin/getDataBaseInfo.wk".format(hostIP)
        #data_url = "http://dr-epic.vicp.io:34005/bin/getDataBaseInfo.wk"
        headers = {'Content-Type': 'application/json'}  # 设置请求头 告诉服务器请求携带的是json格式的数据

        cookie_filename = 'cookie.txt'
        cookie_aff = http.cookiejar.MozillaCookieJar(cookie_filename)
        cookie_aff.load(cookie_filename, ignore_discard=True, ignore_expires=True)
        handler = urllib.request.HTTPCookieProcessor(cookie_aff)
        opener = urllib.request.build_opener(handler)
        # 使用cookie登陆get_url
        # n.rpc.http_service.getDataBaseInfo(
        #hist_data_info={"link":"Serial4.储能battery@电网总功率","startTime":"2019-03-11 14:00:00","endTime": "2019-03-11 14:10:59"}

        get_request = urllib.request.Request(url=data_url, data=json.dumps(hist_data_info).encode(encoding='UTF8'),
                                             headers=headers)
        get_response = opener.open(get_request)
        data_recv = json.loads(get_response.read().decode())
        print(data_recv)
        if not data_recv["result"]:  # cookie过期获取不成功,重新登录
            if self.login():
                return self.getDataBaseInfo(hist_data_info=hist_data_info)
            else:
                logger.warning("Login failed! Query database failed!")
                return None

        return data_recv["data"]

    @rpc
    def getAlertInfo(self, alert_data_info=None):
        """
        :param
        alert_data_info = {}
        Name:        String|Array
        当参数值的类型为String时，表示一个点名，例如："API.TEST设备@YC1"，如果不写@和@后的点名，\
        将会查询以这个字符串为开头的所有点名的报警信息，例："API.TEST设备"，将会查询"API"下"TEST设备"下的所有点的报警信息；\
        当参数值的类型为Array时，表示一个点列表，例如：["API.TEST设备@YC1", "API.TEST设备@YC2",…]
        AlertType:        String|Array
        可选值："UpperLimit", "LowerLimit", " Open", " Close"，分别代表：上限报警、下限报警、分闸报警、合闸报警
        StartTime:        String
        开始时间，查询历史数据的起始时间，格式：YYYY-MM-DD HH:mm:ss，例：2017-12-29 00:00:00
        EndTime:        String
        结束时间，查询历史数据的终止时间，格式：YYYY-MM-DD HH:mm:ss，例：2017-12-30 23:59:59
        """
        if alert_data_info is None:
            return None
        alert_url = "http://{}/bin/getAlertInfo.wk".format(hostIP)
        headers = {'Content-Type': 'application/json'}  # 设置请求头 告诉服务器请求携带的是json格式的数据

        cookie_filename = 'cookie.txt'
        cookie_aff = http.cookiejar.MozillaCookieJar(cookie_filename)
        cookie_aff.load(cookie_filename, ignore_discard=True, ignore_expires=True)

        handler = urllib.request.HTTPCookieProcessor(cookie_aff)
        opener = urllib.request.build_opener(handler)
        # 使用cookie登陆get_url
        # alert_data_info = {
        #     "Name": "Serial3.pv@逆变器温度",
        #     "AlertType": ["UpperLimit", "LowerLimit", "Open", " Close"],
        #     "StartTime": "2018-12-19 10:00:00",
        #     "EndTime": "2018-12-19 11:00:14"
        # }
        get_request = urllib.request.Request(url=alert_url, data=json.dumps(alert_data_info).encode(encoding='UTF8'),
                                             headers=headers)
        get_response = opener.open(get_request)
        data_recv = json.loads(get_response.read().decode())
        if not data_recv["result"]:  # cookie过期获取不成功,重新登录
            if self.login():
                return self.getAlertInfo(alert_data_info=alert_data_info)
            else:
                logger.warning("Login failed! Query alert data failed!")
                return None

        return data_recv["data"]

    def login(self):
        # hostIP1="dr-epic.vicp.io:34005"
        url = 'http://{}/bin/login.wk'.format(hostIP)
        login = {
            "name": "admin",
            "password": "e10adc3949ba59abbe56e057f20f883e"
            # 123456: e10adc3949ba59abbe56e057f20f883e
            # drepic-admin: 8101b4b26d1356032c472ee6945a8caa
        }

        headers = {'Content-Type': 'application/json'}  # 设置请求头 告诉服务器请求携带的是json格式的数据
        # request = urllib.request.Request(url=url, headers=headers,
        #                                  data=json.dumps(values).encode(encoding='UTF8'))  # 需要通过encode设置编码 要不会报错
        #
        # response = urllib.request.urlopen(request)  # 发送请求
        #
        #
        # logInfo = response.read().decode()  # 读取对象 将返回的二进制数据转成string类型
        # print(logInfo)

        # headers = {'User-Agent': r'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36' \
        #          r' (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36', 'Connection': 'keep-alive'}
        cookie_filename = 'cookie.txt'
        cookie_aff = http.cookiejar.MozillaCookieJar(cookie_filename)
        handler = urllib.request.HTTPCookieProcessor(cookie_aff)
        opener = urllib.request.build_opener(handler)

        request = urllib.request.Request(url=url, data=json.dumps(login).encode(encoding='UTF8'), headers=headers)
        try:
            response = opener.open(request)
        except urllib.error.URLError as e:
            logger.error("login failed: "+e.reason)
            return False
        cookie_aff.save(ignore_discard=True, ignore_expires=True)

        if json.loads(response.read().decode())["result"]:
            return True
        else:
            return False

        # logInfo = response.read().decode()  # 读取对象 将返回的二进制数据转成string类型
        # print(logInfo)

        # for item in cookie_aff:
        #     print('Name =' + item.name)
        #     print('Value =' + item.value)
        # 使用cookie登陆get_url
        # get_data = {
        #     "link": "Serial1.battery@电网总功率",
        #     "startTime": "2018-12-17 15:00:00",
        #     "endTime": "2018-12-17 15:00:30"
        # }
        # get_request = urllib.request.Request(url=data_url, data=json.dumps(get_data).encode(encoding='UTF8'),
        #                                      headers=headers)
        # get_response = opener.open(get_request)
        # print(get_response.read().decode())

    # @http('GET', '/get/<int:value>')
    # def get_method(self, request, value):
    #     return json.dumps({'value': value})
    #
    # @http('POST', '/post')
    # def do_post(self, request):
    #     return u"received: {}".format(request.get_data(as_text=True))

